﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing.Printing;
using System.IO;
using System.Drawing;
using System.Printing;
using System.Management;


namespace Business
{
    public class Printer
    {
        public long id { get; set; }
        public string name { get; set; }
        public string status { get; set; }
        public string nameNstatus { get; set; }
    }
    public class PrintJob
    {
        public long id { get; set; }
        public string printername { get; set; }
        public string status { get; set; }
    }

    public class Sentence
    {
        public Font fontType { get; set; }
        public string stringContetnt { get; set; }
    }

    public class PrinterManagement
    {
        FosIntelEntities _en = new FosIntelEntities();
        //private StreamReader streamToPrint;
        private Font printFont;
        private List<Sentence> printsentences = new List<Sentence>();

        public List<Printer> GetAllPrinter()
        {
            // Enum added printer
            String pkInstalledPrinters;
            List<Printer> PrinterList = new List<Printer>();
            List<fos_Printer> addedList = new List<fos_Printer>();

            try
            {
                for (int i = 0; i < PrinterSettings.InstalledPrinters.Count; i++)
                {
                    pkInstalledPrinters = PrinterSettings.InstalledPrinters[i];
                    System.Diagnostics.Debug.WriteLine(pkInstalledPrinters + " (" + "Added" + ")");
                    long printerID = AddPrinter(pkInstalledPrinters, ref addedList);
                    Printer printerobj = new Printer();
                    printerobj.id = printerID;
                    printerobj.name = pkInstalledPrinters;
                    printerobj.status = "Added";
                    printerobj.nameNstatus = pkInstalledPrinters + " (" + "Added" + ")";
                    PrinterList.Add(printerobj);
                }
            }
            catch
            {
                // Error will occur in Azure because can't access installed printer
            }

            // Enum non added printer
            List<fos_Printer> dblist = (from a in _en.fos_Printer
                                        select a).ToList();


            var nonAddedPrinter = (from a in dblist
                                   where !addedList.Contains(a)
                                   select a).ToList();



            foreach (fos_Printer xprinter in nonAddedPrinter)
            {
                Printer printerobj = new Printer();
                printerobj.id = xprinter.Id;
                printerobj.name = xprinter.PrinterName;
                printerobj.status = "Not Added";
                printerobj.nameNstatus = xprinter.PrinterName + " (" + "Not Added" + ")";
                System.Diagnostics.Debug.WriteLine(printerobj.nameNstatus);
                PrinterList.Add(printerobj);
            }
            return PrinterList;
        }

        public long AddPrinter(String printerName, ref List<fos_Printer> addedList)
        {
            fos_Printer printer = (from a in _en.fos_Printer
                                   where a.PrinterName == printerName
                                   select a).FirstOrDefault();
            if (printer != null)
            {

                addedList.Add(printer);
                return printer.Id;
            }
            //throw new Exception("Email address is already a registered user!");

            // Not activated yet
            printer = new fos_Printer();
            printer.IsDeleted = 0;
            printer.LastModifiedBy = "System Management";
            printer.PrinterIP = "0.0.0.0";
            printer.PrinterName = printerName;

            printer.CreatedBy = "System Management";
            printer.CreatedDate = DateTime.Now;
            printer.LastModifiedDate = DateTime.Now;

            _en.fos_Printer.Add(printer);
            _en.SaveChanges();
            addedList.Add(printer);
            return printer.Id;
        }


        /// <summary>
        /// Obsolete Method
        /// Not going to take in order directly
        /// </summary>
        /// <param name="order"></param>
        /// <returns></returns>
        public List<Sentence> PrintOrderSentence(fos_Order order)
        {

            List<Sentence> retval = new List<Sentence>();
            Sentence st = new Sentence();
            decimal subtotal = 0;

            st.stringContetnt = "Order ID: " + order.Id.ToString() + ", OrderBy:" + order.CreatedBy;
            st.fontType = new Font("Verdana", 12);
            retval.Add(st);
            st = new Sentence();

            st.stringContetnt = "Order Date:" + order.CreatedDate;
            st.fontType = new Font("Arial", 10);
            retval.Add(st);
            st = new Sentence();

            st.stringContetnt = "** Pickup Time:" + order.PickUpDateTime;
            st.fontType = new Font("Arial", 11);
            retval.Add(st);
            st = new Sentence();

            st.stringContetnt = "*Remark: " + order.Remark;
            st.fontType = new Font("Arial", 10);
            retval.Add(st);
            st = new Sentence();

            List<fos_orderdetails> listItems = new List<fos_orderdetails>();

            foreach (fos_orderdetails item in order.fos_orderdetails)
            {
                decimal total = 0;// = Convert.ToDecimal(item.FoodQuantity) * item.FoodPrice;
                st.stringContetnt = item.FoodName;
                st.fontType = new Font("Arial", 12);
                retval.Add(st);
                st = new Sentence();

                total = (decimal)item.FoodQuantity * (decimal)item.FoodPrice;
                subtotal += total;
                st.stringContetnt = item.FoodPrice.ToString() + " x " + item.FoodQuantity.ToString() + " = " + total;
                st.fontType = new Font("Arial", 10);
                retval.Add(st);
                st = new Sentence();
            }
            st.stringContetnt = "Sub Total($) = " + subtotal.ToString();
            st.fontType = new Font("Arial", 12);
            retval.Add(st);
            return retval;
        }

        public List<Sentence> PrintOrderSentenceUpdate(IGrouping<string, PrintOrderDetail> orderList)
        {
            List<Sentence> retval = new List<Sentence>();
            Sentence st = new Sentence();
            decimal subtotal = 0;
            int i = 0;
            foreach (PrintOrderDetail order in orderList)
            {
                if (i == 0)
                {
                    st.stringContetnt = "Order ID: " + order.OrderID.ToString();
                    st.fontType = new Font(FontFamily.GenericSansSerif, 12,FontStyle.Bold);
                    retval.Add(st);
                    st = new Sentence();

                    st.stringContetnt = "Order By:" + order.OrderBy;
                    st.fontType = new Font(FontFamily.GenericMonospace,10,FontStyle.Bold);
                    retval.Add(st);
                    st = new Sentence();

                    st.stringContetnt = "Order Date:" + order.OrderTime;
                    st.fontType = new Font("Arial", 10);
                    retval.Add(st);
                    st = new Sentence();

                    st.stringContetnt = "** Pickup Time:" + order.PickUpDateTime;
                    st.fontType = new Font("Arial", 10);
                    retval.Add(st);
                    st = new Sentence();

                    st.stringContetnt = "** Remark: " + order.OrderRemark;
                    st.fontType = new Font(FontFamily.GenericMonospace, 10, FontStyle.Underline);
                    retval.Add(st);
                    st = new Sentence();
                }
                
                st.stringContetnt = order.FoodName;
                if (order.Condiment.Trim() != "" && order.Condiment != null)
                {
                    st.stringContetnt = st.stringContetnt + "* (" + order.Condiment + ")";
                }
                st.fontType = new Font("Arial", 11,FontStyle.Bold);
                retval.Add(st);
                st = new Sentence();

                decimal total = 0;
                total = (decimal)order.FoodQuantity * (decimal)order.FoodPrice;
                subtotal += total;
                st.stringContetnt = "$" +  order.FoodPrice.ToString() + " x " + order.FoodQuantity.ToString() + " = $" + total;
                st.fontType = new Font("Arial", 10);
                retval.Add(st);
                st = new Sentence();


                i++;
            }
            st.stringContetnt = "---------------------------------------------";
            st.fontType = new Font("Arial", 12);
            retval.Add(st);
            st = new Sentence();

            st.stringContetnt = "Sub Total($) = " + subtotal.ToString();
            st.fontType = new Font("Arial", 12);
            retval.Add(st);
            st = new Sentence();
            st.stringContetnt = "---------------------------------------------";
            st.fontType = new Font("Arial", 12);
            retval.Add(st);
            st = new Sentence();


            return retval;
        }

        public void PrintSentences(List<Sentence> sentences, string printerName)
        {
            printsentences = new List<Sentence>();
            printsentences = sentences;
            try
            {
                //string printer = "EASYSET PBP_A7";
                string printer = printerName;
                try
                {
                    PrintDocument pd = new PrintDocument();
                    pd.PrintPage += new PrintPageEventHandler
                       (this.pd_PrintPageSentences);
                    pd.PrinterSettings.PrinterName = printer;

                    pd.DocumentName = "FlexFood Ordering";
                    pd.Print();
                }
                finally
                {
                    //streamToPrint.Close();
                }
            }
            catch (Exception ex)
            {
                System.Diagnostics.Debug.WriteLine(ex.Message);
            }
        }

        private void pd_PrintPageSentences(object sender, PrintPageEventArgs ev)
        {
            //float linesPerPage = 0;
            float yPos = 0;
            int count = 0;
            float leftMargin = ev.MarginBounds.Left - 90;
            float topMargin = ev.MarginBounds.Top - 90;
            float linewidth = ev.MarginBounds.Width;
            float yPosPrev = topMargin;
            int maxLineWidth = 260;
            string line = null;

            foreach (Sentence st in printsentences)
            {

                printFont = st.fontType;
                line = st.stringContetnt;

                SizeF stringSize = new SizeF();
                stringSize = ev.Graphics.MeasureString(line, printFont);

                if (stringSize.Width > maxLineWidth)
                {

                    // Calculate if the st is within line width

                    string xtraOneCharStr = "";

                    int charCount = 0;
                    SizeF xtraOneCharStrSize = new SizeF();
                    foreach (char c in line)
                    {
                        charCount++;
                        xtraOneCharStr = xtraOneCharStr + c;                        
                        xtraOneCharStrSize = ev.Graphics.MeasureString(xtraOneCharStr, printFont);
                        
                        if (xtraOneCharStrSize.Width > maxLineWidth || charCount == line.Count())
                        {
                            // calculate the height
                            yPos = yPosPrev + (printFont.GetHeight(ev.Graphics));

                            //if yes, draw line
                            ev.Graphics.DrawString(xtraOneCharStr, printFont, Brushes.Black,
                                leftMargin, yPos, new StringFormat());

                            yPosPrev = yPos;
                            xtraOneCharStr = "";
                        }
                    }
                }
                else
                {
                    //Print as per normal

                    // Measure string.
                    stringSize = new SizeF();
                    stringSize = ev.Graphics.MeasureString(line, printFont);

                    // calculate the height
                    yPos = yPosPrev + (printFont.GetHeight(ev.Graphics));

                    //if yes, draw line
                    ev.Graphics.DrawString(line, printFont, Brushes.Black,
                        leftMargin, yPos, new StringFormat());

                    // increment
                    yPosPrev = yPos;
                    count++;
                }
            }

            line = null;

            // If more lines exist, print another page. 
            if (line != null)
                ev.HasMorePages = true;
            else
                ev.HasMorePages = false;
        }

        private void pd_PrintPageSentencesOld(object sender, PrintPageEventArgs ev)
        {
            //float linesPerPage = 0;
            float yPos = 0;
            int count = 0;
            float leftMargin = ev.MarginBounds.Left - 90;
            float topMargin = ev.MarginBounds.Top - 90;
            float linewidth = ev.MarginBounds.Width;
            float yPosPrev = topMargin;
            int maxLineWidth = 260;
            string line = null;

            foreach (Sentence st in printsentences)
            {

                printFont = st.fontType;
                line = st.stringContetnt;

                SizeF stringSize = new SizeF();
                stringSize = ev.Graphics.MeasureString(line, printFont);

                if (stringSize.Width > maxLineWidth)
                {

                    // Calculate if the st is within line width
                    string fixStr = "";
                    string xtraOneCharStr = "";

                    int charCount = 0;
                    SizeF xtraOneCharStrSize = new SizeF();
                    foreach (char c in line)
                    {
                        charCount++;
                        xtraOneCharStr = fixStr + c;
                        xtraOneCharStrSize = ev.Graphics.MeasureString(xtraOneCharStr, printFont);

                        if (xtraOneCharStrSize.Width > maxLineWidth || charCount == line.Count())
                        {
                            if (charCount == line.Count()) fixStr = xtraOneCharStr;

                            // calculate the height
                            yPos = yPosPrev + (printFont.GetHeight(ev.Graphics));

                            //if yes, draw line
                            ev.Graphics.DrawString(fixStr, printFont, Brushes.Black,
                                leftMargin, yPos, new StringFormat());

                            yPosPrev = yPos;
                            fixStr = "" + c;
                        }
                        else
                        {
                            fixStr = xtraOneCharStr;
                        }
                    }
                }
                else
                {
                    //Print as per normal

                    // Measure string.
                    stringSize = new SizeF();
                    stringSize = ev.Graphics.MeasureString(line, printFont);

                    // calculate the height
                    yPos = yPosPrev + (printFont.GetHeight(ev.Graphics));

                    //if yes, draw line
                    ev.Graphics.DrawString(line, printFont, Brushes.Black,
                        leftMargin, yPos, new StringFormat());

                    // increment
                    yPosPrev = yPos;
                    count++;
                }
            }

            line = null;

            // If more lines exist, print another page. 
            if (line != null)
                ev.HasMorePages = true;
            else
                ev.HasMorePages = false;
        }

        public List<PrintJob> GetAllPrintJob()
        {
            List<PrintJob> printJobs = new List<PrintJob>();
            String pkInstalledPrinters;
            try
            {
                for (int i = 0; i < PrinterSettings.InstalledPrinters.Count; i++)   // get all installed printer
                {
                    pkInstalledPrinters = PrinterSettings.InstalledPrinters[i];
                    System.Diagnostics.Debug.WriteLine("Installed Printer:" + pkInstalledPrinters);
                    LocalPrintServer printServer = new LocalPrintServer();
                    PrintQueue pq = printServer.GetPrintQueue(pkInstalledPrinters); // get print job by printer name

                    string jobList = "";
                    string statusReport = "";
                    int idcount = 0;
                    pq.Refresh();
                    PrintJobInfoCollection jobs = pq.GetPrintJobInfoCollection();
                    foreach (PrintSystemJobInfo job in jobs)
                    {

                        // Since the user may not be able to articulate which job is problematic, 
                        // present information about each job the user has submitted. 
                        if (job.Name == "FlexFood Ordering")
                        {
                            idcount++;
                            PrintJob pj = new PrintJob();
                            pj.id = idcount;
                            pj.printername = pq.Name;
                            jobList = "\tID:" + job.JobIdentifier + ", Submitter:" + job.Submitter;
                            jobList = jobList + "\n\t\tSubmitted Time:" + job.TimeJobSubmitted;
                            SpotTroubleUsingProperties(ref statusReport, pq);
                            jobList = jobList + "\n\t.Status Report:" + statusReport;
                            //System.Diagnostics.Debug.WriteLine(jobList);
                            pj.status = jobList;
                            printJobs.Add(pj);
                        }
                    }// end for each print job  
                }
            }
            catch
            {
                // Error occur in Azure
            }
            return printJobs;
        }

        internal static void SpotTroubleUsingProperties(ref String statusReport, PrintQueue pq)
        {
            if (pq.HasPaperProblem)
            {
                statusReport = statusReport + "Has a paper problem. ";
            }
            if (!(pq.HasToner))
            {
                statusReport = statusReport + "Is out of toner. ";
            }
            if (pq.IsDoorOpened)
            {
                statusReport = statusReport + "Has an open door. ";
            }
            if (pq.IsInError)
            {
                statusReport = statusReport + "Is in an error state. ";
            }
            if (pq.IsNotAvailable)
            {
                statusReport = statusReport + "Is not available. ";
            }
            if (pq.IsOffline)
            {
                statusReport = statusReport + "Is off line. ";
            }
            if (pq.IsOutOfMemory)
            {
                statusReport = statusReport + "Is out of memory. ";
            }
            if (pq.IsOutOfPaper)
            {
                statusReport = statusReport + "Is out of paper. ";
            }
            if (pq.IsOutputBinFull)
            {
                statusReport = statusReport + "Has a full output bin. ";
            }
            if (pq.IsPaperJammed)
            {
                statusReport = statusReport + "Has a paper jam. ";
            }
            if (pq.IsPaused)
            {
                statusReport = statusReport + "Is paused. ";
            }
            if (pq.IsTonerLow)
            {
                statusReport = statusReport + "Is low on toner. ";
            }
            if (pq.NeedUserIntervention)
            {
                statusReport = statusReport + "Needs user intervention. ";
            }

            // Check if queue is even available at this time of day 
            // The following method is defined in the complete example.
            //ReportAvailabilityAtThisTime(ref statusReport, pq);

        }//end SpotTroubleUsingProperties
    }
}
